package compendiumAid.application.loadElement
{
	import compendiumAid.application.Element;
	import compendiumAid.domain.ElementUtil;
	import compendiumAid.domain.model.SessionModel;
	
	import flash.events.TimerEvent;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	
	import mx.controls.Alert;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	
	import org.spicefactory.lib.task.Task;

	public class LoadElementTask extends Task
	{
		private static const COOKIE_HEADERS:Object = {'Cookie':'resultsPerPage=20; iPlanetDirectoryPro=f4823ba3-798e-4875-b7f9-58442775788b; BIGipServerWWWPool1=3792701706.20480.0000; ASP.NET_SessionId=fd12b51cbvyoxfps1cbsquul; BIGipServerWWWCOMPPool1=705693962.20480.0000; DnDWebsiteSettings=0=0; __utma=28542179.1233327179.1283048888.1283048888.1283048888.1; __utmz=28542179.1283048888.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=d%26d%20compendium'};
		private static const ERROR_TEXT:String = "<body style=\"width:560px\"><div align=\"center\"><p style=\"color: #F00\">ERROR</p><p>There was an error retrieving this element</p><p style=\"color: #F00\">ERROR</p></div></body>";
		private static const DISPLAY_URL:String = "http://www.wizards.com/dndinsider/compendium/display.aspx?page=";
		private static const LOGIN_URL:String = "http://www.wizards.com/dndinsider/compendium/login.aspx?page=";
		private static const MAX_FAULT_ENCOUNTERS:Number = 3;
		private static const MAX_LOGIN_ATTEMPTS:Number = 5;
		private static const POST:String = "POST";
		private static const GET:String = "GET";
		
		private static var elementCache:Dictionary;	
		
		private var service:HTTPService;
		private var element:Element;
		private var sessionModel:SessionModel;
		private var loginAttempts:Number;
		private var faultEncounters:Number;
		
		public function LoadElementTask(element:Element, sessionModel:SessionModel)
		{
			this.element = element;
			this.sessionModel = sessionModel;
			
			loginAttempts = 0;
			faultEncounters = 0;
			
			setCancelable( false );
			setSuspendable( false );
			setSkippable( false );
		}
		
		override protected function doStart():void
		{
			if (elementCache == null)
			{
				elementCache = new Dictionary();
			}
			
			if (elementCache[element.elementVO.id] != null)
			{
				sendElement();
			}
			else
			{
				if (sessionModel.succesfulLogin)
				{
					display();
				}
				else
				{
					login();
				}				
			}
		}
		
		private function login():void
		{
			service = setupService(POST);
			service.url = setupURL(LOGIN_URL);
			service.send(sessionModel.parameters);
		}
		
		private function display():void
		{
			service = setupService(GET);
			service.url = setupURL(DISPLAY_URL);
			service.send();
		}
		
		private function setupService(method:String):HTTPService
		{
			var service:HTTPService;
			
			service = new HTTPService();
			service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
			service.method = method;
			service.headers = COOKIE_HEADERS;
			
			service.addEventListener(ResultEvent.RESULT, onResult);
			service.addEventListener(FaultEvent.FAULT,   onFault);
				
			return service;
		}
		
		private function setupURL(baseURL:String):String	
		{
			var url:String;
			
			url = baseURL + element.elementVO.classification.toLowerCase() + "&id=" + element.elementVO.id;
			
			return url;
		}
		
		private function onResult(event:ResultEvent):void
		{
			var resultString:String = event.result.toString();
			
			faultEncounters = 0;
			
			if (resultString.indexOf('login.aspx?') == -1) 
			{
				sessionModel.succesfulLogin = true;
				loginAttempts = 0;
				
				elementCache[element.elementVO.id] = ElementUtil.cleanHTMLString(resultString);
				
				cleanup();
				
				sendElement();	
			}
			else
			{
				if (loginAttempts < MAX_LOGIN_ATTEMPTS)
				{
					trace("Attempting to login");
					
					var viewstatePattern:RegExp = /id="__VIEWSTATE" value="(.*?)"/;
					var eventvalidationPattern:RegExp = /id="__EVENTVALIDATION" value="(.*?)"/;
					
					var viewstateMatches:Object = viewstatePattern.exec(resultString);
					var eventvalidationMatches:Object = eventvalidationPattern.exec(resultString);
					
					var viewstateMatch:String = viewstateMatches[1];
					var eventvalidationMatch:String = eventvalidationMatches[1];
					
					sessionModel.parameters['__VIEWSTATE'] = viewstateMatch;
					sessionModel.parameters['__EVENTVALIDATION'] = eventvalidationMatch;
					
					loginAttempts++;
					
					login();
				}
				else
				{
					Alert.show("Unable to login.  Check your credentials to make sure they are accurate.", "Authentication Error");
				}
			}
		}
		
		private function onFault(event:FaultEvent):void
		{
			if (faultEncounters < MAX_FAULT_ENCOUNTERS)
			{
				faultEncounters++;
				
				setFunctionTimeout(login, 1000);
				setFunctionTimeout(display, 1000);
			}
			else
			{
				trace("HTTP Service Fault");
	
				Alert.show("HTTP Service Error: " + event.statusCode + ".  " + event.fault.faultString, "Service Error");
				
				element.htmlText = ERROR_TEXT;
				
				cleanup();
			}
		}
		
		private function cleanup():void
		{
			if (service != null)
			{
				service.removeEventListener(ResultEvent.RESULT, onResult);
				service.removeEventListener(FaultEvent.FAULT,   onFault);
			}
			
			service = null;
		}
		
		private function sendElement():void
		{
			element.htmlText = elementCache[element.elementVO.id] as String;
			
			super.complete();
		}
		
		private function setFunctionTimeout(timeoutFunction:Function, timeout:Number):void
		{
			var wrapperFunction:Function = function wrapper(event:TimerEvent):void { timeoutFunction(); };
			var timer:Timer = new Timer(timeout, 1);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, wrapperFunction, false, 0, true);
			timer.start();
		}
	}
}